home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gdevxcmp.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  26.9 KB  |  889 lines

  1. /* Copyright (C) 1999 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gdevxcmp.c,v 1.2 2000/09/19 19:00:23 lpd Exp $ */
  20. /* X Windows color mapping */
  21. #include "math_.h"
  22. #include "x_.h"
  23. #include "gx.h"            /* for gx_bitmap; includes std.h */
  24. #include "gserrors.h"
  25. #include "gxdevice.h"
  26. #include "gdevx.h"
  27.  
  28. /* ---------------- Utilities ---------------- */
  29.  
  30. private void
  31. gs_x_free(void *obj, client_name_t cname)
  32. {
  33.     gs_free(obj, 0 /*ignored*/, 0 /*ignored*/, cname);
  34. }
  35.  
  36. /* ---------------- Color mapping setup / cleanup ---------------- */
  37.  
  38. #if HaveStdCMap
  39.  
  40. /* Install a standard color map in the device. */
  41. /* Sets std_cmap.* except for free_map. */
  42. private bool
  43. set_cmap_values(x11_cmap_values_t *values, int maxv, int mult)
  44. {
  45.     int i;
  46.  
  47.     if (maxv < 1 || maxv > 63 || (maxv & (maxv + 1)) ||
  48.     (mult & (mult - 1))
  49.     )
  50.     return false;
  51.     values->cv_shift = 16 - small_exact_log2(maxv + 1);
  52.     for (i = 0; i <= maxv; ++i)
  53.     values->nearest[i] = X_max_color_value * i / maxv;
  54.     for (i = 0; mult != (1 << i); ++i)
  55.     DO_NOTHING;
  56.     values->pixel_shift = i;
  57.     return true;
  58. }
  59. private void
  60. set_std_cmap(gx_device_X *xdev, XStandardColormap *map)
  61. {
  62.     xdev->cman.std_cmap.map = map;
  63.     xdev->cman.std_cmap.fast =
  64.     set_cmap_values(&xdev->cman.std_cmap.red, map->red_max, map->red_mult) &&
  65.     set_cmap_values(&xdev->cman.std_cmap.green, map->green_max, map->green_mult) &&
  66.     set_cmap_values(&xdev->cman.std_cmap.blue, map->blue_max, map->blue_mult);
  67. }
  68.  
  69. /* Get the Standard colormap if available. */
  70. /* Uses: dpy, scr, cmap. */
  71. private XStandardColormap *
  72. x_get_std_cmap(gx_device_X * xdev, Atom prop)
  73. {
  74.     int i;
  75.     XStandardColormap *scmap, *sp;
  76.     int nitems;
  77.  
  78.     if (XGetRGBColormaps(xdev->dpy, RootWindowOfScreen(xdev->scr),
  79.              &scmap, &nitems, prop))
  80.     for (i = 0, sp = scmap; i < nitems; i++, sp++)
  81.         if (xdev->cmap == sp->colormap)
  82.         return sp;
  83.  
  84.     return NULL;
  85. }
  86.  
  87. /* Create a Standard colormap for a TrueColor or StaticGray display. */
  88. /* Return true if the allocation was successful. */
  89. /* Uses: vinfo.  Sets: std_cmap.*. */
  90. private bool
  91. alloc_std_cmap(gx_device_X *xdev, bool colored)
  92. {
  93.     XStandardColormap *cmap = XAllocStandardColormap();
  94.  
  95.     if (cmap == 0)
  96.     return false;        /* can't allocate */
  97.     /*
  98.      * Some buggy X servers (including XFree86) don't set any of the
  99.      * _mask values for StaticGray visuals.  Compensate for that here.
  100.      */
  101.     if ((cmap->red_max = xdev->vinfo->red_mask) == 0) {
  102.     cmap->red_max = (1 << xdev->vinfo->depth) - 1;
  103.     cmap->red_mult = 1;
  104.     } else {
  105.     for (cmap->red_mult = 1; (cmap->red_max & 1) == 0;) {
  106.         cmap->red_max >>= 1;
  107.         cmap->red_mult <<= 1;
  108.     }
  109.     }
  110.     if (colored) {
  111.     for (cmap->green_max = xdev->vinfo->green_mask, cmap->green_mult = 1;
  112.          (cmap->green_max & 1) == 0;
  113.          ) {
  114.         cmap->green_max >>= 1;
  115.         cmap->green_mult <<= 1;
  116.     }
  117.     for (cmap->blue_max = xdev->vinfo->blue_mask, cmap->blue_mult = 1;
  118.          (cmap->blue_max & 1) == 0;
  119.          ) {
  120.         cmap->blue_max >>= 1;
  121.         cmap->blue_mult <<= 1;
  122.     }
  123.     }
  124.     set_std_cmap(xdev, cmap);
  125.     xdev->cman.std_cmap.free_map = true;
  126.     return true;
  127. }
  128.  
  129. #endif
  130.  
  131. /* Allocate the dynamic color table, if needed and possible. */
  132. /* Uses: vinfo, cman.num_rgb.  Sets: cman.dynamic.*. */
  133. private void
  134. alloc_dynamic_colors(gx_device_X * xdev, int num_colors)
  135. {
  136.     if (num_colors > 0) {
  137.     xdev->cman.dynamic.colors = (x11_color_t **)
  138.         gs_malloc(sizeof(x11_color_t *), xdev->cman.num_rgb,
  139.               "x11 cman.dynamic.colors");
  140.     if (xdev->cman.dynamic.colors) {
  141.         int i;
  142.  
  143.         xdev->cman.dynamic.size = xdev->cman.num_rgb;
  144.         xdev->cman.dynamic.shift = 16 - xdev->vinfo->bits_per_rgb;
  145.         for (i = 0; i < xdev->cman.num_rgb; i++)
  146.         xdev->cman.dynamic.colors[i] = NULL;
  147.         xdev->cman.dynamic.max_used = min(256, num_colors);
  148.         xdev->cman.dynamic.used = 0;
  149.     }
  150.     }
  151. }
  152.  
  153. /* Allocate an X color, updating the reverse map. */
  154. /* Return true if the allocation was successful. */
  155. private bool
  156. x_alloc_color(gx_device_X *xdev, XColor *xcolor)
  157. {
  158.     x11_rgb_t rgb;
  159.  
  160.     rgb.rgb[0] = xcolor->red;
  161.     rgb.rgb[1] = xcolor->green;
  162.     rgb.rgb[2] = xcolor->blue;
  163.     if (!XAllocColor(xdev->dpy, xdev->cmap, xcolor))
  164.     return false;
  165.     if (xcolor->pixel < xdev->cman.color_to_rgb.size) {
  166.     x11_rgb_t *pxrgb = &xdev->cman.color_to_rgb.values[xcolor->pixel];
  167.  
  168.     memcpy(pxrgb->rgb, rgb.rgb, sizeof(rgb.rgb));
  169.     pxrgb->defined = true;
  170.     }
  171.     return true;
  172. }
  173.  
  174. /* Free X colors, updating the reverse map. */
  175. private void
  176. x_free_colors(gx_device_X *xdev, x_pixel *pixels /*[count]*/, int count)
  177. {
  178.     int i;
  179.     x_pixel pixel;
  180.  
  181.     XFreeColors(xdev->dpy, xdev->cmap, pixels, count, 0);
  182.     for (i = 0; i < count; ++i)
  183.     if ((pixel = pixels[i]) < xdev->cman.color_to_rgb.size)
  184.         xdev->cman.color_to_rgb.values[pixel].defined = false;
  185. }
  186.  
  187. /* Free a partially filled color cube or ramp. */
  188. /* Uses: dpy, cmap.  Uses and sets: cman.dither_ramp. */
  189. private void
  190. free_ramp(gx_device_X * xdev, int num_used, int size)
  191. {
  192.     if (num_used - 1 > 0)
  193.     x_free_colors(xdev, xdev->cman.dither_ramp + 1, num_used - 1);
  194.     gs_x_free(xdev->cman.dither_ramp, "x11_setup_colors");
  195.     xdev->cman.dither_ramp = NULL;
  196. }
  197.  
  198. /* Allocate and fill in a color cube or ramp. */
  199. /* Return true if the operation succeeded. */
  200. /* Uses: dpy, cmap, foreground, background, cman.color_mask. */
  201. /* Sets: cman.dither_ramp. */
  202. private bool
  203. setup_cube(gx_device_X * xdev, int ramp_size, bool colors)
  204. {
  205.     int step, num_entries;
  206.     int max_rgb = ramp_size - 1;
  207.     int index;
  208.  
  209.     if (colors) {
  210.     num_entries = ramp_size * ramp_size * ramp_size;
  211.     step = 1;        /* all colors */
  212.     } else {
  213.     num_entries = ramp_size;
  214.     step = (ramp_size + 1) * ramp_size + 1;        /* gray only */
  215.     }
  216.  
  217.     xdev->cman.dither_ramp =
  218.     (x_pixel *) gs_malloc(sizeof(x_pixel), num_entries,
  219.                   "gdevx setup_cube");
  220.     if (xdev->cman.dither_ramp == NULL)
  221.     return false;
  222.  
  223.     xdev->cman.dither_ramp[0] = xdev->foreground;
  224.     xdev->cman.dither_ramp[num_entries - 1] = xdev->background;
  225.     for (index = 1; index < num_entries - 1; index++) {
  226.     int rgb_index = index * step;
  227.     int q = rgb_index / ramp_size,
  228.         r = q / ramp_size,
  229.         g = q % ramp_size,
  230.         b = rgb_index % ramp_size;
  231.     XColor xc;
  232.  
  233.     xc.red = (X_max_color_value * r / max_rgb) & xdev->cman.color_mask.red;
  234.     xc.green = (X_max_color_value * g / max_rgb) & xdev->cman.color_mask.green;
  235.     xc.blue = (X_max_color_value * b / max_rgb) & xdev->cman.color_mask.blue;
  236.     if (!x_alloc_color(xdev, &xc)) {
  237.         free_ramp(xdev, index, num_entries);
  238.         return false;
  239.     }
  240.     xdev->cman.dither_ramp[index] = xc.pixel;
  241.     }
  242.  
  243.     return true;
  244. }
  245.  
  246. /* Setup color mapping. */
  247. int
  248. gdev_x_setup_colors(gx_device_X * xdev)
  249. {
  250.     char palette =
  251.     ((xdev->vinfo->class != StaticGray) &&
  252.      (xdev->vinfo->class != GrayScale) ? 'C' :    /* Color */
  253.      (xdev->vinfo->colormap_size > 2) ? 'G' :        /* GrayScale */
  254.      'M');        /* MonoChrome */
  255.  
  256.     if (xdev->ghostview) {
  257.     Atom gv_colors = XInternAtom(xdev->dpy, "GHOSTVIEW_COLORS", False);
  258.     Atom type;
  259.     int format;
  260.     unsigned long nitems, bytes_after;
  261.     char *buf;
  262.  
  263.     /* Delete property if explicit dest is given */
  264.     if (XGetWindowProperty(xdev->dpy, xdev->win, gv_colors, 0,
  265.                    256, (xdev->dest != 0), XA_STRING,
  266.                    &type, &format, &nitems, &bytes_after,
  267.                    (unsigned char **)&buf) == 0 &&
  268.         type == XA_STRING) {
  269.         nitems = sscanf(buf, "%*s %ld %ld", &(xdev->foreground),
  270.                 &(xdev->background));
  271.         if (nitems != 2 || (*buf != 'M' && *buf != 'G' && *buf != 'C')) {
  272.         eprintf("Malformed GHOSTVIEW_COLOR property.\n");
  273.         return_error(gs_error_rangecheck);
  274.         }
  275.         palette = max(palette, *buf);
  276.     }
  277.     } else {
  278.     if (xdev->palette[0] == 'c')
  279.         xdev->palette[0] = 'C';
  280.     else if (xdev->palette[0] == 'g')
  281.         xdev->palette[0] = 'G';
  282.     else if (xdev->palette[0] == 'm')
  283.         xdev->palette[0] = 'M';
  284.     palette = max(palette, xdev->palette[0]);
  285.     }
  286.  
  287.     /* set up color mappings here */
  288.     xdev->cman.color_mask.red = xdev->cman.color_mask.green =
  289.     xdev->cman.color_mask.blue = X_max_color_value -
  290.       (X_max_color_value >> xdev->vinfo->bits_per_rgb);
  291.     xdev->cman.match_mask = xdev->cman.color_mask; /* default */
  292.     xdev->cman.num_rgb = 1 << xdev->vinfo->bits_per_rgb;
  293.  
  294. #if HaveStdCMap
  295.     xdev->cman.std_cmap.map = NULL;
  296.     xdev->cman.std_cmap.free_map = false;
  297. #endif
  298.     xdev->cman.dither_ramp = NULL;
  299.     xdev->cman.dynamic.colors = NULL;
  300.     xdev->cman.dynamic.size = 0;
  301.     xdev->cman.dynamic.used = 0;
  302.     switch (xdev->vinfo->depth) {
  303.     case 1: case 2: case 4: case 8: case 16: case 24: case 32:
  304.     xdev->color_info.depth = xdev->vinfo->depth;
  305.     break;
  306.     case 15:
  307.     xdev->color_info.depth = 16;
  308.     break;
  309.     default:
  310.     eprintf1("Unsupported X visual depth: %d\n", xdev->vinfo->depth);
  311.     return_error(gs_error_rangecheck);
  312.     }
  313.     {    /* Set up the reverse map from pixel values to RGB. */
  314.     int count = 1 << min(xdev->color_info.depth, 8);
  315.  
  316.     xdev->cman.color_to_rgb.values =
  317.         (x11_rgb_t *)gs_malloc(sizeof(x11_rgb_t), count,
  318.                    "gdevx color_to_rgb");
  319.     if (xdev->cman.color_to_rgb.values) {
  320.         int i;
  321.  
  322.         for (i = 0; i < count; ++i)
  323.         xdev->cman.color_to_rgb.values[i].defined = false;
  324.         xdev->cman.color_to_rgb.size = count;
  325.     } else
  326.         xdev->cman.color_to_rgb.size = 0;
  327.     }
  328.     switch ((int)palette) {
  329.     case 'C':
  330.     xdev->color_info.num_components = 3;
  331.     xdev->color_info.max_gray =
  332.         xdev->color_info.max_color = xdev->cman.num_rgb - 1;
  333. #if HaveStdCMap
  334.     /* Get a standard color map if available */
  335.     if (xdev->vinfo->visual == DefaultVisualOfScreen(xdev->scr)) {
  336.         xdev->cman.std_cmap.map = x_get_std_cmap(xdev, XA_RGB_DEFAULT_MAP);
  337.     } else {
  338.         xdev->cman.std_cmap.map = x_get_std_cmap(xdev, XA_RGB_BEST_MAP);
  339.     }
  340.     if (xdev->cman.std_cmap.map ||
  341.         (xdev->vinfo->class == TrueColor && alloc_std_cmap(xdev, true))
  342.         ) {
  343.         xdev->color_info.dither_grays = xdev->color_info.dither_colors =
  344.         min(xdev->cman.std_cmap.map->red_max,
  345.             min(xdev->cman.std_cmap.map->green_max,
  346.             xdev->cman.std_cmap.map->blue_max)) + 1;
  347.         if (xdev->cman.std_cmap.map)
  348.         set_std_cmap(xdev, xdev->cman.std_cmap.map);
  349.     } else
  350. #endif
  351.         /* Otherwise set up a rgb cube of our own */
  352.         /* The color cube is limited to about 1/2 of the available */
  353.         /* colormap, the user specified maxRGBRamp (usually 5), */
  354.         /* or the number of representable colors */
  355. #define CUBE(r) (r*r*r)
  356. #define CBRT(r) pow(r, 1.0/3.0)
  357.     {
  358.         int ramp_size =
  359.         min((int)CBRT(xdev->vinfo->colormap_size / 2.0),
  360.             min(xdev->maxRGBRamp, xdev->cman.num_rgb));
  361.  
  362.         while (!xdev->cman.dither_ramp && ramp_size >= 2) {
  363.         xdev->color_info.dither_grays =
  364.             xdev->color_info.dither_colors = ramp_size;
  365.         if (!setup_cube(xdev, ramp_size, true)) {
  366. #ifdef DEBUG
  367.             eprintf3("Warning: failed to allocate %dx%dx%d RGB cube.\n",
  368.                  ramp_size, ramp_size, ramp_size);
  369. #endif
  370.             ramp_size--;
  371.             continue;
  372.         }
  373.         }
  374.  
  375.         if (!xdev->cman.dither_ramp) {
  376.         goto grayscale;
  377.         }
  378.     }
  379.  
  380.     /* Allocate the dynamic color table. */
  381.     alloc_dynamic_colors(xdev, CUBE(xdev->cman.num_rgb) -
  382.                  CUBE(xdev->color_info.dither_colors));
  383. #undef CUBE
  384. #undef CBRT
  385.     break;
  386.     case 'G':
  387. grayscale:
  388.     xdev->color_info.num_components = 1;
  389.     xdev->color_info.max_gray = xdev->cman.num_rgb - 1;
  390. #if HaveStdCMap
  391.     /* Get a standard color map if available */
  392.     xdev->cman.std_cmap.map = x_get_std_cmap(xdev, XA_RGB_GRAY_MAP);
  393.     if (xdev->cman.std_cmap.map ||
  394.         (xdev->vinfo->class == StaticGray && alloc_std_cmap(xdev, false))
  395.         ) {
  396.         xdev->color_info.dither_grays =
  397.         xdev->cman.std_cmap.map->red_max + 1;
  398.         if (xdev->cman.std_cmap.map)
  399.         set_std_cmap(xdev, xdev->cman.std_cmap.map);
  400.     } else
  401. #endif
  402.         /* Otherwise set up a gray ramp of our own */
  403.         /* The gray ramp is limited to about 1/2 of the available */
  404.         /* colormap, the user specified maxGrayRamp (usually 128), */
  405.         /* or the number of representable grays */
  406.     {
  407.         int ramp_size = min(xdev->vinfo->colormap_size / 2,
  408.                 min(xdev->maxGrayRamp, xdev->cman.num_rgb));
  409.  
  410.         while (!xdev->cman.dither_ramp && ramp_size >= 3) {
  411.         xdev->color_info.dither_grays = ramp_size;
  412.         if (!setup_cube(xdev, ramp_size, false)) {
  413. #ifdef DEBUG
  414.             eprintf1("Warning: failed to allocate %d level gray ramp.\n",
  415.                  ramp_size);
  416. #endif
  417.             ramp_size /= 2;
  418.             continue;
  419.         }
  420.         }
  421.         if (!xdev->cman.dither_ramp) {
  422.         goto monochrome;
  423.         }
  424.     }
  425.  
  426.     /* Allocate the dynamic color table. */
  427.     alloc_dynamic_colors(xdev, xdev->cman.num_rgb -
  428.                  xdev->color_info.dither_grays);
  429.     break;
  430.     case 'M':
  431. monochrome:
  432.     xdev->color_info.num_components = 1;
  433.     xdev->color_info.max_gray = 1;
  434.     xdev->color_info.dither_grays = 2;
  435.     break;
  436.     default:
  437.     eprintf1("Unknown palette: %s\n", xdev->palette);
  438.     if (xdev->cman.color_to_rgb.values) {
  439.         gs_x_free(xdev->cman.color_to_rgb.values, "gdevx color_to_rgb");
  440.         xdev->cman.color_to_rgb.values = 0;
  441.     }
  442.     return_error(gs_error_rangecheck);
  443.     }
  444.  
  445. #if HaveStdCMap
  446.     /*
  447.      * When comparing colors, if not halftoning, we must only compare as
  448.      * many bits as actually fit in a pixel, even if the hardware has more.
  449.      */
  450.     if (!gx_device_must_halftone(xdev)) {
  451.     if (xdev->cman.std_cmap.map) {
  452.         xdev->cman.match_mask.red &=
  453.         X_max_color_value << xdev->cman.std_cmap.red.cv_shift;
  454.         xdev->cman.match_mask.green &=
  455.         X_max_color_value << xdev->cman.std_cmap.green.cv_shift;
  456.         xdev->cman.match_mask.blue &=
  457.         X_max_color_value << xdev->cman.std_cmap.blue.cv_shift;
  458.     }
  459.     }
  460. #endif
  461.  
  462.     return 0;
  463. }
  464.  
  465. /* Free the dynamic colors when doing an erasepage. */
  466. /* Uses: cman.dynamic.*.  Sets: cman.dynamic.used. */
  467. void
  468. gdev_x_free_dynamic_colors(gx_device_X *xdev)
  469. {
  470.     if (xdev->cman.dynamic.colors) {
  471.     int i;
  472.     x11_color_t *xcp;
  473.     x11_color_t *next;
  474.  
  475.     for (i = 0; i < xdev->cman.dynamic.size; i++) {
  476.         for (xcp = xdev->cman.dynamic.colors[i]; xcp; xcp = next) {
  477.         next = xcp->next;
  478.         if (xcp->color.pad)
  479.             x_free_colors(xdev, &xcp->color.pixel, 1);
  480.         gs_x_free(xcp, "x11_dynamic_color");
  481.         }
  482.         xdev->cman.dynamic.colors[i] = NULL;
  483.     }
  484.     xdev->cman.dynamic.used = 0;
  485.     }
  486. }
  487.  
  488. /*
  489.  * Free storage and color map entries when closing the device.
  490.  * Uses and sets: cman.{std_cmap.map, dither_ramp, dynamic.colors,
  491.  * color_to_rgb}.  Uses: cman.std_cmap.free_map.
  492.  */
  493. void
  494. gdev_x_free_colors(gx_device_X *xdev)
  495. {
  496.     if (xdev->cman.std_cmap.free_map) {
  497.     /* XFree is declared as taking a char *, not a void *! */
  498.     XFree((void *)xdev->cman.std_cmap.map);
  499.     xdev->cman.std_cmap.free_map = false;
  500.     }
  501.     xdev->cman.std_cmap.map = 0;
  502.     if (xdev->cman.dither_ramp)
  503.     gs_x_free(xdev->cman.dither_ramp, "x11 dither_colors");
  504.     if (xdev->cman.dynamic.colors) {
  505.     gdev_x_free_dynamic_colors(xdev);
  506.     gs_x_free(xdev->cman.dynamic.colors, "x11 cman.dynamic.colors");
  507.     xdev->cman.dynamic.colors = NULL;
  508.     }
  509.     if (xdev->cman.color_to_rgb.values) {
  510.     gs_x_free(xdev->cman.color_to_rgb.values, "x11 color_to_rgb");
  511.     xdev->cman.color_to_rgb.values = NULL;
  512.     xdev->cman.color_to_rgb.size = 0;
  513.     }
  514. }
  515.  
  516. /* ---------------- Driver color mapping calls ---------------- */
  517.  
  518. /* Define a table for computing N * X_max_color_value / D for 0 <= N <= D, */
  519. /* 1 <= D <= 7. */
  520. /* This requires a multiply and a divide otherwise; */
  521. /* integer multiply and divide are slow on all platforms. */
  522. #define CV_FRACTION(n, d) ((X_color_value)(X_max_color_value * (n) / (d)))
  523. #define ND(n, d) CV_FRACTION(n, d)
  524. private const X_color_value cv_tab1[] = {
  525.     ND(0,1), ND(1,1)
  526. };
  527. private const X_color_value cv_tab2[] = {
  528.     ND(0,2), ND(1,2), ND(2,2)
  529. };
  530. private const X_color_value cv_tab3[] = {
  531.     ND(0,3), ND(1,3), ND(2,3), ND(3,3)
  532. };
  533. private const X_color_value cv_tab4[] = {
  534.     ND(0,4), ND(1,4), ND(2,4), ND(3,4), ND(4,4)
  535. };
  536. private const X_color_value cv_tab5[] = {
  537.     ND(0,5), ND(1,5), ND(2,5), ND(3,5), ND(4,5), ND(5,5)
  538. };
  539. private const X_color_value cv_tab6[] = {
  540.     ND(0,6), ND(1,6), ND(2,6), ND(3,6), ND(4,6), ND(5,6), ND(6,6)
  541. };
  542. private const X_color_value cv_tab7[] = {
  543.     ND(0,7), ND(1,7), ND(2,7), ND(3,7), ND(4,7), ND(5,7), ND(6,7), ND(7,7)
  544. };
  545. #undef ND
  546. private const X_color_value *const cv_tables[] =
  547. {
  548.     0, cv_tab1, cv_tab2, cv_tab3, cv_tab4, cv_tab5, cv_tab6, cv_tab7
  549. };
  550.  
  551. /* Some C compilers don't declare the abs function in math.h. */
  552. /* Provide one of our own. */
  553. private inline int
  554. iabs(int x)
  555. {
  556.     return (x < 0 ? -x : x);
  557. }
  558.  
  559. /* Map RGB values to a pixel value. */
  560. gx_color_index
  561. gdev_x_map_rgb_color(gx_device * dev,
  562.              gx_color_value r, gx_color_value g, gx_color_value b)
  563. {
  564.     gx_device_X *const xdev = (gx_device_X *) dev;
  565.  
  566.     /* X and ghostscript both use shorts for color values. */
  567.     /* Set drgb to the nearest color that the device can represent. */
  568.     X_color_value dr = r & xdev->cman.color_mask.red;
  569.     X_color_value dg = g & xdev->cman.color_mask.green;
  570.     X_color_value db = b & xdev->cman.color_mask.blue;
  571.  
  572.     {
  573.     /* Foreground and background get special treatment: */
  574.     /* They may be mapped to other colors. */
  575.     /* Set mrgb to the color to be used for match testing. */
  576.     X_color_value mr = r & xdev->cman.match_mask.red;
  577.     X_color_value mg = g & xdev->cman.match_mask.green;
  578.     X_color_value mb = b & xdev->cman.match_mask.blue;
  579.  
  580.     if ((mr | mg | mb) == 0) {    /* i.e., all 0 */
  581.         if_debug4('C', "[cX]%u,%u,%u => foreground = %lu\n",
  582.               r, g, b, (ulong) xdev->foreground);
  583.         return xdev->foreground;
  584.     }
  585.     if (mr == xdev->cman.match_mask.red &&
  586.         mg == xdev->cman.match_mask.green &&
  587.         mb == xdev->cman.match_mask.blue
  588.         ) {
  589.         if_debug4('C', "[cX]%u,%u,%u => background = %lu\n",
  590.               r, g, b, (ulong) xdev->background);
  591.         return xdev->background;
  592.     }
  593.     }
  594.  
  595. #define CV_DENOM (gx_max_color_value + 1)
  596.  
  597. #if HaveStdCMap
  598.     /* check the standard colormap first */
  599.     if (xdev->cman.std_cmap.map) {
  600.     const XStandardColormap *cmap = xdev->cman.std_cmap.map;
  601.  
  602.     if (gx_device_has_color(xdev)) {
  603.         uint cr, cg, cb;    /* rgb cube indices */
  604.         X_color_value cvr, cvg, cvb;    /* color value on cube */
  605.  
  606.         if (xdev->cman.std_cmap.fast) {
  607.         cr = r >> xdev->cman.std_cmap.red.cv_shift;
  608.         cvr = xdev->cman.std_cmap.red.nearest[cr];
  609.         cg = g >> xdev->cman.std_cmap.green.cv_shift;
  610.         cvg = xdev->cman.std_cmap.green.nearest[cg];
  611.         cb = b >> xdev->cman.std_cmap.blue.cv_shift;
  612.         cvb = xdev->cman.std_cmap.blue.nearest[cb];
  613.         } else {
  614.         cr = r * (cmap->red_max + 1) / CV_DENOM;
  615.         cg = g * (cmap->green_max + 1) / CV_DENOM;
  616.         cb = b * (cmap->blue_max + 1) / CV_DENOM;
  617.         cvr = X_max_color_value * cr / cmap->red_max;
  618.         cvg = X_max_color_value * cg / cmap->green_max;
  619.         cvb = X_max_color_value * cb / cmap->blue_max;
  620.         }
  621.         if ((iabs((int)r - (int)cvr) & xdev->cman.match_mask.red) == 0 &&
  622.         (iabs((int)g - (int)cvg) & xdev->cman.match_mask.green) == 0 &&
  623.         (iabs((int)b - (int)cvb) & xdev->cman.match_mask.blue) == 0) {
  624.         gx_color_index pixel =
  625.             (xdev->cman.std_cmap.fast ?
  626.              (cr << xdev->cman.std_cmap.red.pixel_shift) +
  627.              (cg << xdev->cman.std_cmap.green.pixel_shift) +
  628.              (cb << xdev->cman.std_cmap.blue.pixel_shift) :
  629.              cr * cmap->red_mult + cg * cmap->green_mult +
  630.              cb * cmap->blue_mult) + cmap->base_pixel;
  631.  
  632.         if_debug4('C', "[cX]%u,%u,%u (std cmap) => %lu\n",
  633.               r, g, b, pixel);
  634.         return pixel;
  635.         }
  636.         if_debug3('C', "[cX]%u,%u,%u (std cmap fails)\n", r, g, b);
  637.     } else {
  638.         uint cr;
  639.         X_color_value cvr;
  640.  
  641.         cr = r * (cmap->red_max + 1) / CV_DENOM;
  642.         cvr = X_max_color_value * cr / cmap->red_max;
  643.         if ((iabs((int)r - (int)cvr) & xdev->cman.match_mask.red) == 0) {
  644.         gx_color_index pixel = cr * cmap->red_mult + cmap->base_pixel;
  645.  
  646.         if_debug2('C', "[cX]%u (std cmap) => %lu\n", r, pixel);
  647.         return pixel;
  648.         }
  649.         if_debug1('C', "[cX]%u (std cmap fails)\n", r);
  650.     }
  651.     } else
  652. #endif
  653.  
  654.     /* If there is no standard colormap, check the dither cube/ramp */
  655.     if (xdev->cman.dither_ramp) {
  656.     if (gx_device_has_color(xdev)) {
  657.         uint cr, cg, cb;    /* rgb cube indices */
  658.         X_color_value cvr, cvg, cvb;    /* color value on cube */
  659.         int dither_rgb = xdev->color_info.dither_colors;
  660.         uint max_rgb = dither_rgb - 1;
  661.  
  662.         cr = r * dither_rgb / CV_DENOM;
  663.         cg = g * dither_rgb / CV_DENOM;
  664.         cb = b * dither_rgb / CV_DENOM;
  665.         if (max_rgb < countof(cv_tables)) {
  666.         const ushort *cv_tab = cv_tables[max_rgb];
  667.  
  668.         cvr = cv_tab[cr];
  669.         cvg = cv_tab[cg];
  670.         cvb = cv_tab[cb];
  671.         } else {
  672.         cvr = CV_FRACTION(cr, max_rgb);
  673.         cvg = CV_FRACTION(cg, max_rgb);
  674.         cvb = CV_FRACTION(cb, max_rgb);
  675.         }
  676.         if ((iabs((int)r - (int)cvr) & xdev->cman.match_mask.red) == 0 &&
  677.         (iabs((int)g - (int)cvg) & xdev->cman.match_mask.green) == 0 &&
  678.         (iabs((int)b - (int)cvb) & xdev->cman.match_mask.blue) == 0) {
  679.         gx_color_index pixel =
  680.             xdev->cman.dither_ramp[CUBE_INDEX(cr, cg, cb)];
  681.  
  682.         if_debug4('C', "[cX]%u,%u,%u (dither cube) => %lu\n",
  683.               r, g, b, pixel);
  684.         return pixel;
  685.         }
  686.         if_debug3('C', "[cX]%u,%u,%u (dither cube fails)\n", r, g, b);
  687.     } else {
  688.         uint cr;
  689.         X_color_value cvr;
  690.         int dither_grays = xdev->color_info.dither_grays;
  691.         uint max_gray = dither_grays - 1;
  692.  
  693.         cr = r * dither_grays / CV_DENOM;
  694.         cvr = (X_max_color_value * cr / max_gray);
  695.         if ((iabs((int)r - (int)cvr) & xdev->cman.match_mask.red) == 0) {
  696.         gx_color_index pixel = xdev->cman.dither_ramp[cr];
  697.  
  698.         if_debug2('C', "[cX]%u (dither ramp) => %lu\n", r, pixel);
  699.         return pixel;
  700.         }
  701.         if_debug1('C', "[cX]%u (dither ramp fails)\n", r);
  702.     }
  703.     }
  704.  
  705.     /* Finally look through the list of dynamic colors */
  706.     if (xdev->cman.dynamic.colors) {
  707.     int i = (dr ^ dg ^ db) >> xdev->cman.dynamic.shift;
  708.     x11_color_t *xcp = xdev->cman.dynamic.colors[i];
  709.     x11_color_t *prev = NULL;
  710.     XColor xc;
  711.  
  712.     for (; xcp; prev = xcp, xcp = xcp->next)
  713.         if (xcp->color.red == dr && xcp->color.green == dg &&
  714.         xcp->color.blue == db) {
  715.         /* Promote the found entry to the front of the list. */
  716.         if (prev) {
  717.             prev->next = xcp->next;
  718.             xcp->next = xdev->cman.dynamic.colors[i];
  719.             xdev->cman.dynamic.colors[i] = xcp;
  720.         }
  721.         if (xcp->color.pad) {
  722.             if_debug4('C', "[cX]%u,%u,%u (dynamic) => %lu\n",
  723.                   r, g, b, (ulong) xcp->color.pixel);
  724.             return xcp->color.pixel;
  725.         } else {
  726.             if_debug3('C', "[cX]%u,%u,%u (dynamic) => missing\n",
  727.                   r, g, b);
  728.             return gx_no_color_index;
  729.         }
  730.         }
  731.  
  732.     /* If not in our list of dynamic colors, */
  733.     /* ask the X server and add an entry. */
  734.     /* First check if dynamic table is exhausted */
  735.     if (xdev->cman.dynamic.used > xdev->cman.dynamic.max_used) {
  736.         if_debug3('C', "[cX]%u,%u,%u (dynamic) => full\n", r, g, b);
  737.         return gx_no_color_index;
  738.     }
  739.     xcp = (x11_color_t *)
  740.         gs_malloc(sizeof(x11_color_t), 1, "x11_dynamic_color");
  741.     if (!xcp)
  742.         return gx_no_color_index;
  743.     xc.red = xcp->color.red = dr;
  744.     xc.green = xcp->color.green = dg;
  745.     xc.blue = xcp->color.blue = db;
  746.     xcp->next = xdev->cman.dynamic.colors[i];
  747.     xdev->cman.dynamic.colors[i] = xcp;
  748.     xdev->cman.dynamic.used++;
  749.     if (x_alloc_color(xdev, &xc)) {
  750.         xcp->color.pixel = xc.pixel;
  751.         xcp->color.pad = true;
  752.         if_debug5('c', "[cX]0x%x,0x%x,0x%x (dynamic) => added [%d]%lu\n",
  753.               dr, dg, db, xdev->cman.dynamic.used - 1,
  754.               (ulong)xc.pixel);
  755.         return xc.pixel;
  756.     } else {
  757.         xcp->color.pad = false;
  758.         if_debug3('c', "[cX]0x%x,0x%x,0x%x (dynamic) => can't alloc\n",
  759.               dr, dg, db);
  760.         return gx_no_color_index;
  761.     }
  762.     }
  763.     if_debug3('C', "[cX]%u,%u,%u fails\n", r, g, b);
  764.     return gx_no_color_index;
  765. #undef CV_DENOM
  766. }
  767.  
  768.  
  769. /* Map a pixel value back to r-g-b. */
  770. int
  771. gdev_x_map_color_rgb(gx_device * dev, gx_color_index color,
  772.              gx_color_value prgb[3])
  773. {
  774.     const gx_device_X *const xdev = (const gx_device_X *) dev;
  775. #if HaveStdCMap
  776.     const XStandardColormap *cmap = xdev->cman.std_cmap.map;
  777. #endif
  778.  
  779.     if (color == xdev->foreground) {
  780.     prgb[0] = prgb[1] = prgb[2] = 0;
  781.     return 0;
  782.     }
  783.     if (color == xdev->background) {
  784.     prgb[0] = prgb[1] = prgb[2] = gx_max_color_value;
  785.     return 0;
  786.     }
  787.     if (color < xdev->cman.color_to_rgb.size) {
  788.     const x11_rgb_t *pxrgb = &xdev->cman.color_to_rgb.values[color];
  789.  
  790.     if (pxrgb->defined) {
  791.         prgb[0] = pxrgb->rgb[0];
  792.         prgb[1] = pxrgb->rgb[1];
  793.         prgb[2] = pxrgb->rgb[2];
  794.         return 0;
  795.     }
  796. #if HaveStdCMap
  797.     }
  798.  
  799.     /* Check the standard colormap. */
  800.     if (cmap) {
  801.     if (color >= cmap->base_pixel) {
  802.         x_pixel value = color - cmap->base_pixel;
  803.         uint r = (value / cmap->red_mult) % (cmap->red_max + 1);
  804.         uint g = (value / cmap->green_mult) % (cmap->green_max + 1);
  805.         uint b = (value / cmap->blue_mult) % (cmap->blue_max + 1);
  806.  
  807.         if (value == r * cmap->red_mult + g * cmap->green_mult +
  808.         b * cmap->blue_mult) {
  809.         /* When mapping color buckets back to specific colors,
  810.          * we can choose to map them to the darkest shades
  811.          * (e.g., 0, 1/3, 2/3), to the lightest shades (e.g.,
  812.          * 1/3-epsilon, 2/3-epsilon, 1-epsilon), to the middle
  813.          * shades (e.g., 1/6, 1/2, 5/6), or for maximum range
  814.          * (e.g., 0, 1/2, 1).  The last of these matches the
  815.          * assumptions of the halftoning code, so that is what
  816.          * we choose.
  817.          */
  818.         prgb[0] = r * gx_max_color_value / cmap->red_max;
  819.         prgb[1] = g * gx_max_color_value / cmap->green_max;
  820.         prgb[2] = b * gx_max_color_value / cmap->blue_max;
  821.         return 0;
  822.         }
  823.     }
  824.     }
  825.     if (color < xdev->cman.color_to_rgb.size) {
  826. #endif
  827.     /* Error -- undefined pixel value. */
  828.     return_error(gs_error_unknownerror);
  829.     }
  830.     /*
  831.      * Check the dither cube/ramp.  This is hardly ever used, since if
  832.      * there are few enough colors to require dithering, the pixel values
  833.      * are likely to be small enough to index color_to_rgb.
  834.      */
  835.     if (xdev->cman.dither_ramp) {
  836.     if (gx_device_has_color(xdev)) {
  837.         int size = xdev->color_info.dither_colors;
  838.         int size3 = size * size * size;
  839.         int i;
  840.  
  841.         for (i = 0; i < size3; ++i)
  842.         if (xdev->cman.dither_ramp[i] == color) {
  843.             uint max_rgb = size - 1;
  844.             uint q = i / size,
  845.             r = q / size,
  846.             g = q % size,
  847.             b = i % size;
  848.  
  849.             /*
  850.              * See above regarding the choice of color mapping
  851.              * algorithm.
  852.              */
  853.             prgb[0] = r * gx_max_color_value / max_rgb;
  854.             prgb[1] = g * gx_max_color_value / max_rgb;
  855.             prgb[2] = b * gx_max_color_value / max_rgb;
  856.             return 0;
  857.         }
  858.     } else {
  859.         int size = xdev->color_info.dither_grays;
  860.         int i;
  861.  
  862.         for (i = 0; i < size; ++i)
  863.         if (xdev->cman.dither_ramp[i] == color) {
  864.             prgb[0] = prgb[1] = prgb[2] =
  865.             i * gx_max_color_value / (size - 1);
  866.             return 0;
  867.         }
  868.     }
  869.     }
  870.  
  871.     /* Finally, search the list of dynamic colors. */
  872.     if (xdev->cman.dynamic.colors) {
  873.     int i;
  874.     const x11_color_t *xcp;
  875.  
  876.     for (i = xdev->cman.dynamic.size; --i >= 0;)
  877.         for (xcp = xdev->cman.dynamic.colors[i]; xcp; xcp = xcp->next)
  878.         if (xcp->color.pixel == color && xcp->color.pad) {
  879.             prgb[0] = xcp->color.red;
  880.             prgb[1] = xcp->color.green;
  881.             prgb[2] = xcp->color.blue;
  882.             return 0;
  883.         }
  884.     }
  885.  
  886.     /* Not found -- not possible! */
  887.     return_error(gs_error_unknownerror);
  888. }
  889.